import React, { Component } from "react";

import { EaseInOutQuart } from "../Tools";
import { DIRECTION, itvTime, speed, maxWeight, f } from "../define";

import "../style/buildingBody.css";

class ElevatorBody extends Component {
  constructor(props) {
    super(props);
  }
  state = {
    intervalID: 0,
    currentWeight: 0,
    position: 1,
    direction: DIRECTION.NONE,
    showDirection: DIRECTION.NONE,
  };
  componentDidMount() {
    this.props.onRef(this);
  }
  GetWeight = () => {
    return this.state.currentWeight;
  };
  AddWeight = (weight) => {
    this.setState({
      currentWeight: this.state.currentWeight + weight,
    });
  };
  // 为父组件提供修改电梯方向的接口
  SetDirection = (nextDirection, callback = () => {}) => {
    this.setState(
      {
        direction: nextDirection,
      },
      callback
    );
  };
  SetShowDirection = (nextDirection) => {
    this.setState({
      showDirection: nextDirection,
    });
  };
  RunTo = (desFloor, onArrived = () => {}) => {
    desFloor = Number(desFloor);
    // 清除之前的运动轨迹
    clearInterval(this.state.intervalID);

    const distance = itvTime / (1000 / speed); // 需要移动的距离
    // 开始运动
    const localID = setInterval(() => {
      const { position } = this.state;

      // 到达目的楼层停止
      if (position === desFloor) {
        clearInterval(this.state.intervalID);
        // 到达函数
        this.props.onMove();
        onArrived();
        this.SetShowDirection(DIRECTION.NONE);
        return;
      }
      // ——————移动逻辑——————
      // console.log("position, distance", position, distance);
      // 2. 调用MoveTo | 注意：，此处toFixed避免JS浮点运算误差
      if (desFloor > position) {
        this.MoveTo(Number((position + distance).toFixed(2)));
        this.SetShowDirection(DIRECTION.UP);
      } else if (desFloor < position) {
        this.MoveTo(Number((position - distance).toFixed(2)));
        this.SetShowDirection(DIRECTION.DOWN);
      }

      // PS:如果运动间隔的足够短，可能会有误差导致无法到达终点
      if (
        (desFloor > position && desFloor - position < distance) ||
        (desFloor < position && position - desFloor < distance)
      ) {
        this.MoveTo(desFloor);
      }
      // ——————移动逻辑——————
      // 更新PanelUI
      this.props.onMove();
    }, itvTime);

    // 更新返回的间隔ID
    this.setState({
      intervalID: localID,
    });
  };
  // 缓动动画建议自己写，不符合现实中的运动规律
  // 而且目的内未经过楼层的顺风车会有bug
  RunToV2 = (desFloor, onArrived = () => {}) => {
    const { position } = this.state;
    desFloor = Number(desFloor);
    // clearInterval(this.state.intervalID); // 调度系统清理会引起起始时间不断被刷新的问题
    if (this.state.intervalID !== 0) {
      return;
    }

    const second = Math.abs(position - desFloor);
    let decreaseSecond = second * 1000;
    const localID = setInterval(() => {
      decreaseSecond -= f;
      if (decreaseSecond <= 0) {
        clearInterval(localID);
        this.setState({ intervalID: 0 });
        this.MoveTo(desFloor);
        onArrived();
        this.SetShowDirection(DIRECTION.NONE);
        return;
      }
      const newPosition = EaseInOutQuart(decreaseSecond, desFloor, position - desFloor, second * 1000).toFixed(2);
      if (newPosition > this.state.position) {
        this.SetShowDirection(DIRECTION.UP);
      } else if (newPosition < this.state.position) {
        this.SetShowDirection(DIRECTION.DOWN);
      }
      this.MoveTo(newPosition);
      this.props.onMove();
    }, f);

    // 更新返回的间隔ID
    this.setState({
      intervalID: localID,
    });
  };
  // V3：匀加速-匀速-匀减速版本，由于情况较为复杂咱不开发，此处简化为匀速运动
  // a = 2m/s², Vmax = 2m/s
  // (Vmax)² = 2ax  -> x = 1m (达到最大速度所需的加速距离为 1层楼对应的高度)
  // 1. des - src === 1, a = 2m/s² for 0.5m && a = -2m/s² for 0.5m  t总 = √2s
  // 2. des - src === x(x >= 2), a = 2m/s² for 1m && a = 0,v = 2m/s for (x-2)m && a = -2m/s² for 1m  t总 = (1+x*0.5)s
  // 若des,src之间出现需求，则分为下述三种情况
  // 2.1 加速期间（加速只有一层楼距离）
  // 2.1.1 des - newSrc === 1 {如果position > des + 0.5，则无视此需求，直接shift}
  // 2.1.2 des - newSrc === 2 {如果position > des + 1}
  // 2.2 匀速期间
  // 2.3 减速期间
  RunToV3 = (desFloor, onArrived = () => {}) => {};
  MoveTo = (position) => {
    this.setState({
      position,
    });
    // 更新UI
    (function aniloop() {
      document.getElementById("elev-box").style.bottom = (position - 1) * 86 + "px";
      window.requestAnimationFrame(aniloop);
    })();
  };
  getPosition = () => this.state.position;
  getFloor = () => Math.round(this.state.position);
  render() {
    const { position, currentWeight } = this.state;
    return (
      <div className="elevator-info">
        <div className="line">position:{position}</div>
        <div className="line">
          currentWeight:{currentWeight}/{maxWeight}
        </div>
        <div className="line">当前楼层:{this.getFloor()}</div>
      </div>
    );
  }
}

export default ElevatorBody;
